package pipeline

import (
	"blockchain/public/entity"
	"fmt"
	"math"
)
const N=entity.N //节点数
const K=entity.K //主节点数
const BlockSize=entity.BlockSize
const TradeSize=entity.TradeSize
const alpha = 2
const prior =0.4
const clientSeq=499
var currentRound=0
var currentTradeSeq=0
var trades [10000]entity.Trade
var node [N] entity.Node
var primarysSeq [K]int
var replicasSeq [N-K]int
var initialNode=false
var TradeSet [N][5][K*TradeSize] entity.Trade

var chanNodeRecPre_prepare=make([]chan pre_prepareMessage,N)
var FlagPre_prepared=make([][]chan bool,N,N)
var chanPriRecPrepare1=make([]chan prepare1Message,N)
var FlagPrepared1=make([][]chan bool,N,N)
var chanNodeRecPrepare2=make([]chan prepare2Message,N)
var FlagPrepared2=make([][]chan bool,N,N)
var chanPriRecCommit1=make([]chan commit1Message,N)
var FlagCommitted1=make([][]chan bool,N,N)
var chanNodeRecCommit2=make([]chan commit2Message,N)
var FlagCommitted2=make([][]chan bool,N,N)
var chanReply=make(chan commit2Message,K)
var FlagReplied=make([]chan bool,N)
var blockchain[500] entity.Block
var T1,T2,T3,T4,T5 int

var chanPriRecRequest=make([]chan requestMessage,N)
var chanPriRecRequest2=make([]chan requestMessage,N)
var chanNodeRecPre_prepare2=make([]chan pre_prepareMessage,N)
var FlagPre_prepared2=make([][]chan bool,N,N)
var chanPriRecPrepare12=make([]chan prepare1Message,N)
var FlagPrepared12=make([][]chan bool,N,N)
var chanNodeRecPrepare22=make([]chan prepare2Message,N)
var FlagPrepared22=make([][]chan bool,N,N)
var chanPriRecCommit12=make([]chan commit1Message,N)
var FlagCommitted12=make([][]chan bool,N,N)
var chanNodeRecCommit22=make([]chan commit2Message,N)
var FlagCommitted22=make([][]chan bool,N,N)
var chanReply2=make(chan commit2Message,K)
var FlagReplied2=make([]chan bool,N)

var sumrounds=entity.SumRounds
var flagPri=make([]chan bool,N)


func Main(){
	fmt.Printf("使用传统流水线的共识pipeline:N=%d,K=%d,R=%d",N,K,sumrounds)
	updatePrimarys()
	chanNodeRecPre_prepareInitial()
	chanPriRecPrepare1Initial()
	chanNodeRecPrepare2Initial()
	chanPriRecCommit1Initial()
	chanNodeRecCommit2Initial()
	flagInitial()
	currentTradeSeq=0
	for currentRound=0;currentRound<sumrounds+4;currentRound++{
		//fmt.Printf("第%d轮共识：\n",currentRound)
		if currentRound%2==0{
			request(currentRound)
		}else {
			request1(currentRound)
		}
		T5=currentRound
		T4=T5-1
		T3=T4-1
		T2=T3-1
		T1=T2-1
		for i:=range primarysSeq{
			flagPri[primarysSeq[i]]=make(chan bool,1)
			go primaryConsensus(primarysSeq[i])
		}
		for i:=range replicasSeq{
			flagPri[replicasSeq[i]]=make(chan bool,1)
			go replicaConsensus(replicasSeq[i])
		}
		for i:=0;i<N;i++{
			<-flagPri[i]
		}
		if T1>=0{
			if T1%2==0{
				reply(T1)
			}else {
				reply1(T1)
			}
		}
	}
}


func primaryConsensus(priSeq int){
	var flagT1=make(chan bool)
	var flagT2=make(chan bool)
	var flagT3=make(chan bool)
	var flagT4=make(chan bool)
	var flagT5=make(chan bool)
	if T1>=0{
		if T1%2==0{
			go func() {
				commit2(priSeq,T1)
				for i:=0;i<K;i++ {
					<-FlagCommitted2[primarysSeq[i]][priSeq]
					//FlagCommitted2[primarysSeq[i]][priSeq]=make(chan bool,1)
				}
				close(chanNodeRecCommit2[priSeq])

				chanNodeRecCommit2[priSeq]=make(chan commit2Message,K)
				//reply(T1)
				flagT1<-true
				close(flagT1)
			}()
		}else {
			go func() {
				commit21(priSeq,T1)
				for i:=0;i<K;i++{
					<-FlagCommitted22[primarysSeq[i]][priSeq]
					//FlagCommitted22[primarysSeq[i]][priSeq]=make(chan bool,1)
				}
				close(chanNodeRecCommit22[priSeq])

				chanNodeRecCommit22[priSeq]=make(chan commit2Message,K)
				//reply1(T1)
				flagT1<-true
				close(flagT1)
			}()
		}
	}else {
		go func() {
			flagT1<-false
			close(flagT1)
		}()
	}
	if T2>=0{
		if T2%2==0{
			go func() {
				commit1(priSeq,T2)
				for i:=0;i<N;i++{
					<-FlagCommitted1[i][priSeq]
					//FlagCommitted1[i][priSeq]=make(chan bool,1)
				}
				close(chanPriRecCommit1[priSeq])
				flagT2<-true
				close(flagT2)
			}()
		}else {
			go func() {
				commit11(priSeq,T2)
				for i:=0;i<N;i++{
					<-FlagCommitted12[i][priSeq]
					//FlagCommitted12[i][priSeq]=make(chan bool,1)
				}
				close(chanPriRecCommit12[priSeq])
				flagT2<-true
				close(flagT2)
			}()
		}
	}else {

		go func() {
			flagT2<-false
			close(flagT2)
		}()
	}
	if T3>=0{
		if T3%2==0{
			go func() {
				prepare2(priSeq)
				for i:=range primarysSeq {
					<-FlagPrepared2[primarysSeq[i]][priSeq]
					//FlagPrepared2[primarysSeq[i]][priSeq]=make(chan bool,1)
				}
				close(chanNodeRecPrepare2[priSeq])
				flagT3<-true
				close(flagT3)
			}()
		}else {
			go func() {
				prepare21(priSeq)
				for i:=range primarysSeq {
					<-FlagPrepared22[primarysSeq[i]][priSeq]
					//FlagPrepared22[primarysSeq[i]][priSeq]=make(chan bool,1)
				}
				close(chanNodeRecPrepare22[priSeq])
				flagT3<-true
				close(flagT3)
			}()
		}
	}else {
		go func() {
			flagT3<-false
			close(flagT3)
		}()
	}
	if T4>=0{
		if T4%2==0{
			go func() {
				prepare1(priSeq,T4)
				for i:=0;i<N;i++{
					<-FlagPrepared1[i][priSeq]
					//FlagPrepared1[i][priSeq]=make(chan bool,1)
				}
				for i:=0;i<N;i++{
				}
				close(chanPriRecPrepare1[priSeq])
				flagT4<-true
				close(flagT4)
			}()
		}else {
			go func() {
				prepare11(priSeq,T4)
				for i:=0;i<N;i++{
					<-FlagPrepared12[i][priSeq]
					//FlagPrepared12[i][priSeq]=make(chan bool,1)
				}
				for i:=0;i<N;i++{
				}
				close(chanPriRecPrepare12[priSeq])
				flagT4<-true
				close(flagT4)
			}()
		}
	}else {
		go func() {
			flagT4<-false
			close(flagT4)
		}()
	}
	if T5>=0{
		if T5%2==0{
			go func() {
				pre_prepare(priSeq)
				for i:=range primarysSeq{
					<-FlagPre_prepared[primarysSeq[i]][priSeq]
					//FlagPre_prepared[primarysSeq[i]][priSeq]=make(chan bool,1)
				}
				close(chanNodeRecPre_prepare[priSeq])
				flagT5<-true
				close(flagT5)
			}()
		}else {
			go func() {
				pre_prepare1(priSeq)
				for i:=range primarysSeq{
					<-FlagPre_prepared2[primarysSeq[i]][priSeq]
					//FlagPre_prepared2[primarysSeq[i]][priSeq]=make(chan bool,1)
				}
				close(chanNodeRecPre_prepare2[priSeq])
				flagT5<-true
				close(flagT5)
			}()
		}
	}else {
		go func() {
			flagT5<-false
			close(flagT5)
		}()
	}
	<-flagT1
	<-flagT2
	<-flagT3
	<-flagT4
	<-flagT5
	flagPri[priSeq]<-true
	close(flagPri[priSeq])
}


func replicaConsensus(nodeSeq int){
	var flagT4=make(chan bool)
	var flagT2=make(chan bool)
	var flagT1=make(chan bool)

	if T1>=0{
		if T1%2==0{
			go func() {
				for i:=0;i<K;i++{
					<-FlagCommitted2[primarysSeq[i]][nodeSeq]
					//FlagCommitted2[primarysSeq[i]][nodeSeq]=make(chan bool,1)
				}
				close(chanNodeRecCommit2[nodeSeq])

				chanNodeRecCommit2[nodeSeq]=make(chan commit2Message,K)
				//reply(T1)
				flagT1<-true
				close(flagT1)
			}()
		}else {
			go func() {
				for i:=0;i<K;i++ {
					<-FlagCommitted22[primarysSeq[i]][nodeSeq]
					//FlagCommitted22[primarysSeq[i]][nodeSeq]=make(chan bool,1)
				}
				close(chanNodeRecCommit22[nodeSeq])
				chanNodeRecCommit22[nodeSeq]=make(chan commit2Message,K)
				//reply1(T1)
				flagT1<-true
				close(flagT1)
			}()
		}
	}else {

		go func() {
			flagT1<-false
			close(flagT1)
		}()
	}

	if T4>=0{
		if T4%2==0{
			go func() {
				for i:=range primarysSeq{
					<-FlagPre_prepared[primarysSeq[i]][nodeSeq]
					//FlagPre_prepared[primarysSeq[i]][nodeSeq]=make(chan bool,1)
				}
				close(chanNodeRecPre_prepare[nodeSeq])
				prepare1(nodeSeq,T4)
				flagT4<-true
				close(flagT4)
			}()
		}else {
			go func() {
				for i:=range primarysSeq{
					<-FlagPre_prepared2[primarysSeq[i]][nodeSeq]
					//FlagPre_prepared2[primarysSeq[i]][nodeSeq]=make(chan bool,1)
				}
				close(chanNodeRecPre_prepare2[nodeSeq])
				prepare11(nodeSeq,T4)
				flagT4<-true
				close(flagT4)
			}()
		}
	}else {
		go func() {
			flagT4<-false
			close(flagT4)
		}()
	}
	if T2>=0{
		if T2%2==0{
			go func() {
				for i:=0;i<K;i++ {
					<-FlagPrepared2[primarysSeq[i]][nodeSeq]
					//FlagPrepared2[primarysSeq[i]][nodeSeq]=make(chan bool,1)
				}
				close(chanNodeRecPrepare2[nodeSeq])
				commit1(nodeSeq,T2)
				flagT2<-true
				close(flagT2)
			}()
		}else {
			go func() {
				for i:=0;i<K;i++ {
					<-FlagPrepared22[primarysSeq[i]][nodeSeq]
					//FlagPrepared22[primarysSeq[i]][nodeSeq]=make(chan bool,1)
				}
				close(chanNodeRecPrepare22[nodeSeq])
				commit11(nodeSeq,T2)
				flagT2<-true
				close(flagT2)
			}()
		}
	}else {
		go func() {
			flagT2<-false
			close(flagT2)
		}()
	}

	<-flagT4
	<-flagT2
	<-flagT1
	flagPri[nodeSeq]<-true
	close(flagPri[nodeSeq])

}

func chanNodeRecPre_prepareInitial(){
	for i:=0;i<N;i++{
		chanNodeRecPre_prepare[i]=make(chan pre_prepareMessage,K)
		chanNodeRecPre_prepare2[i]=make(chan pre_prepareMessage,K)
	}
}
func chanPriRecPrepare1Initial(){
	for i:=range primarysSeq{
		chanPriRecPrepare1[primarysSeq[i]]=make(chan prepare1Message,N*2/3+1)
		chanPriRecPrepare12[primarysSeq[i]]=make(chan prepare1Message,N*2/3+1)
	}
}

func chanNodeRecPrepare2Initial(){
	for i:=0;i<N;i++{
		chanNodeRecPrepare2[i]=make(chan prepare2Message,K)
		chanNodeRecPrepare22[i]=make(chan prepare2Message,K)
	}
}

func chanPriRecCommit1Initial(){
	for i:=range primarysSeq{
		chanPriRecCommit1[primarysSeq[i]]=make(chan commit1Message,N*2/3+1)
		chanPriRecCommit12[primarysSeq[i]]=make(chan commit1Message,N*2/3+1)
	}
}

func chanNodeRecCommit2Initial(){
	for i:=0;i<N;i++{
		chanNodeRecCommit2[i]=make(chan commit2Message,K)
		chanNodeRecCommit22[i]=make(chan commit2Message,K)
	}
}
func flagInitial() {
	for i:=range primarysSeq {
		FlagPre_prepared[primarysSeq[i]]= make([]chan bool, N)
		FlagPre_prepared2[primarysSeq[i]]= make([]chan bool, N)
	}
	for i:=range primarysSeq {
		for j:=0;j<N;j++{
			FlagPre_prepared[primarysSeq[i]][j]=make(chan bool,1)
			FlagPre_prepared2[primarysSeq[i]][j]=make(chan bool,1)
		}
	}
	for i:=0;i<N;i++{
		FlagPrepared1[i]=make([]chan bool,N)
		FlagPrepared12[i]=make([]chan bool,N)
	}
	for i:=0;i<N;i++{
		for j:=0;j<N;j++{
			FlagPrepared1[i][j]=make(chan bool,1)
			FlagPrepared12[i][j]=make(chan bool,1)
		}
	}

	for i:=range primarysSeq {
		FlagPrepared2[primarysSeq[i]]= make([]chan bool, N)
		FlagPrepared22[primarysSeq[i]]= make([]chan bool, N)
	}
	for i:=range primarysSeq {
		for j:=0;j<N;j++{
			FlagPrepared2[primarysSeq[i]][j]=make(chan bool,1)
			FlagPrepared22[primarysSeq[i]][j]=make(chan bool,1)
		}
	}

	for i:=0;i<N;i++{
		FlagCommitted1[i]=make([]chan bool,N)
		FlagCommitted12[i]=make([]chan bool,N)
	}
	for i:=0;i<N;i++{
		for j:=0;j<N;j++{
			FlagCommitted1[i][j]=make(chan bool,1)
			FlagCommitted12[i][j]=make(chan bool,1)
		}
	}

	for i:=range primarysSeq {
		FlagCommitted2[primarysSeq[i]]= make([]chan bool, N)
		FlagReplied[primarysSeq[i]]=make(chan bool,1)
		FlagCommitted22[primarysSeq[i]]= make([]chan bool, N)
		FlagReplied2[primarysSeq[i]]=make(chan bool,1)
	}
	for i:=range primarysSeq {
		for j:=0;j<N;j++{
			FlagCommitted2[primarysSeq[i]][j]=make(chan bool,1)
			FlagCommitted22[primarysSeq[i]][j]=make(chan bool,1)
		}
	}
	chanReply=make(chan commit2Message,K)
	chanReply2=make(chan commit2Message,K)
}

func setVaildTurn(){
	for i:=0;i<N;i++{
		node[i].VaildTurn = math.Pow(float64(alpha),float64(node[i].ByzantineTurnNum))*float64(node[i].TurnNum)+float64(node[i].PriorNum)
	}
}

func priorNodeSet()  {
	for i:=0;i<K;i++{
		node[i].PriorNum=prior
	}
	for i:=0;i<K;i++{
		node[i].TurnNum=0
		node[i].ByzantineTurnNum=0
	}
	setVaildTurn()
	initialNode=true
}

func updatePrimarys(){
	if initialNode{
		setVaildTurn()
		var nodeSeq [K] int
		for i:=0;i<K;i++{
			max:=0.0
			maxSeq :=0
			for j:=0;j<N;j++{
				if node[j].VaildTurn>max {
					maxSeq=j
					max=node[j].VaildTurn
				}
			}
			nodeSeq[i]=maxSeq
			node[maxSeq].VaildTurn=-1.0
		}
		primarysSeq =nodeSeq
		backupsseqJ :=0
		for i:=0;i<N;i++{
			if node[i].VaildTurn !=-1.0{
				replicasSeq[backupsseqJ]=i
				backupsseqJ++
			}
		}
		setVaildTurn()
	}else{
		priorNodeSet()
		updatePrimarys()
	}
}
